﻿import pandas as pds
import numpy as npy
from sklearn.model_selection import train_test_split
import time

'''
获取并切分数据
训练数据80%
测试数据20%
tr_labels进行了行列转换,为了方便获取分类的list
'''


def get_data():
    csv_data = pds.read_csv(r"iris.csv", header=None)
    x = csv_data.iloc[:, 0:4].as_matrix()
    y = csv_data.iloc[:, 4:5].as_matrix()
    # 切分训练数据和测试数据
    tr_data, te_data, tr_labels, te_labels = train_test_split(x, y, train_size=0.80, test_size=0.20, random_state=20)
    return tr_data, te_data, tr_labels.T, te_labels


'''
训练数据,为朴素贝叶斯算法准备初始数据
'''


def train_data(data: list, labels: list):
    if len(data) != len(labels):
        raise ValueError("长度不一致")
    labels_chance_dict = {}
    labels_count = len(labels)
    distinct_labels = npy.unique(labels)  # 把类别列表去重
    for label in distinct_labels:
        labels_chance_dict[label] = labels.count(label) / labels_count
    vector_dict = {}
    for v, l in zip(data, labels):
        if l not in vector_dict:
            vector_dict[l] = []
        vector_dict[l].append(v)
    return labels_chance_dict, vector_dict


'''
朴素贝叶斯算法的具体实现
t_data测试用的特征数据列表（只针对一个样本）
labels可能的分类
v_dict训练数据中不同分类与特征向量的对应关系
labels_chance训练数据中不同分类出现的概率
'''


def n_bayes(t_data: list, labels: list, v_dict: dict, labels_chance: dict):
    label_p_dict = {}
    for label in labels:
        p = 1
        cur_label_chance = labels_chance[label]
        all_vector = v_dict[label]
        all_vector_size = len(all_vector)
        all_vector = npy.array(all_vector).T
        for i in range(0, len(t_data)):
            cur_vector = list(all_vector[i])
            p *= cur_vector.count(t_data[i]) / all_vector_size
        label_p_dict[label] = p * cur_label_chance
    res_label = sorted(label_p_dict, key=lambda x: label_p_dict[x], reverse=True)[0]
    return res_label



x1, x2, y1, y2 = get_data()
# 把第二个参数转换为list
chance, dict = train_data(x1.tolist(), y1[0].tolist())
n = 0
time1 = time.time()
for x in range(0, len(x2)):
    rst = n_bayes(x2[x], ['versicolor', 'setosa', 'virginica'], dict, chance)
    if rst == y2[x][0]:
        n += 1
time2 = time.time()
rate = n / len(x2)
print("准确率为：" + str(round(rate, 3)))
print("对20%的数据（共150个数据）进行分类大约共耗时：" + str(time2-time1) + "秒")

